home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / futilsrc.zoo / fileutil / src / ln.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-19  |  6.5 KB  |  294 lines

  1. /* `ln' program to create links between files.
  2.    Copyright (C) 1986, 1989-1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by Mike Parker and David MacKenzie. */
  19.  
  20. #ifdef _AIX
  21.  #pragma alloca
  22. #endif
  23. #include <stdio.h>
  24. #include <sys/types.h>
  25. #include <getopt.h>
  26. #include "system.h"
  27. #include "backupfile.h"
  28.  
  29. int link ();
  30.  
  31. #ifdef S_ISLNK
  32. int symlink ();
  33. #endif
  34.  
  35. char *basename ();
  36. enum backup_type get_version ();
  37. int do_link ();
  38. int isdir ();
  39. int yesno ();
  40. void error ();
  41. void strip_trailing_slashes ();
  42. void usage ();
  43.  
  44. /* A pointer to the function used to make links.  This will point to either
  45.    `link' or `symlink'. */
  46. int (*linkfunc) ();
  47.  
  48. /* If nonzero, make symbolic links; otherwise, make hard links.  */
  49. int symbolic_link;
  50.  
  51. /* If nonzero, ask the user before removing existing files.  */
  52. int interactive;
  53.  
  54. /* If nonzero, remove existing files unconditionally.  */
  55. int remove_existing_files;
  56.  
  57. /* If nonzero, list each file as it is moved. */
  58. int verbose;
  59.  
  60. /* If nonzero, allow the superuser to make hard links to directories. */
  61. int hard_dir_link;
  62.  
  63. /* The name by which the program was run, for error messages.  */
  64. char *program_name;
  65.  
  66. struct option long_options[] = 
  67. {
  68.   {"backup", 0, NULL, 'b'},
  69.   {"directory", 0, &hard_dir_link, 1},
  70.   {"force", 0, NULL, 'f'},
  71.   {"interactive", 0, NULL, 'i'},
  72.   {"suffix", 1, NULL, 'S'},
  73.   {"symbolic", 0, &symbolic_link, 1},
  74.   {"verbose", 0, &verbose, 1},
  75.   {"version-control", 1, NULL, 'V'},
  76.   {NULL, 0, NULL, 0}
  77. };
  78.  
  79. void
  80. main (argc, argv)
  81.      int argc;
  82.      char **argv;
  83. {
  84.   int c;
  85.   int errors;
  86.   int make_backups = 0;
  87.   char *version;
  88.  
  89.   version = getenv ("SIMPLE_BACKUP_SUFFIX");
  90.   if (version)
  91.     simple_backup_suffix = version;
  92.   version = getenv ("VERSION_CONTROL");
  93.   program_name = argv[0];
  94.   linkfunc = link;
  95.   symbolic_link = remove_existing_files = interactive = verbose
  96.     = hard_dir_link = 0;
  97.   errors = 0;
  98.  
  99.   while ((c = getopt_long (argc, argv, "bdfisvFS:V:", long_options, (int *) 0))
  100.      != EOF)
  101.     {
  102.       switch (c)
  103.     {
  104.     case 0:            /* Long-named option. */
  105.        break;
  106.     case 'b':
  107.       make_backups = 1;
  108.       break;
  109.     case 'd':
  110.     case 'F':
  111.       hard_dir_link = 1;
  112.       break;
  113.     case 'f':
  114.       remove_existing_files = 1;
  115.       interactive = 0;
  116.       break;
  117.     case 'i':
  118.       remove_existing_files = 0;
  119.       interactive = 1;
  120.       break;
  121.     case 's':
  122. #ifdef S_ISLNK
  123.       symbolic_link = 1;
  124. #else
  125.       error (0, 0, "symbolic links not supported; making hard links");
  126. #endif
  127.       break;
  128.     case 'v':
  129.       verbose = 1;
  130.       break;
  131.     case 'S':
  132.       simple_backup_suffix = optarg;
  133.       break;
  134.     case 'V':
  135.       version = optarg;
  136.       break;
  137.     default:
  138.       usage ();
  139.       break;
  140.     }
  141.     }
  142.   if (optind == argc)
  143.     usage ();
  144.  
  145.   if (make_backups)
  146.     backup_type = get_version (version);
  147.  
  148. #ifdef S_ISLNK
  149.   if (symbolic_link)
  150.     linkfunc = symlink;
  151. #endif
  152.  
  153.   if (optind == argc - 1)
  154.     errors = do_link (argv[optind], ".");
  155.   else if (optind == argc - 2)
  156.     {
  157.       strip_trailing_slashes (argv[optind + 1]);
  158.       errors = do_link (argv[optind], argv[optind + 1]);
  159.     }
  160.   else
  161.     {
  162.       char *to;
  163.  
  164.       to = argv[argc - 1];
  165.       strip_trailing_slashes (to);
  166.       if (!isdir (to))
  167.     error (1, 0, "when making multiple links, last argument must be a directory");
  168.       for (; optind < argc - 1; ++optind)
  169.     errors += do_link (argv[optind], to);
  170.     }
  171.  
  172.   exit (errors != 0);
  173. }
  174.  
  175. /* Make a link NEW to existing file OLD.
  176.    If NEW is a directory, put the link to OLD in that directory.
  177.    Return 1 if there is an error, otherwise 0.  */
  178.  
  179. int
  180. do_link (old, new)
  181.      char *old;
  182.      char *new;
  183. {
  184.   struct stat new_stats;
  185.   char *new_backup = NULL;
  186.  
  187.   strip_trailing_slashes (old);
  188.  
  189.   /* Since link follows symlinks, isdir uses stat instead of lstat. */
  190.   if (!symbolic_link && !hard_dir_link && isdir (old))
  191.     {
  192.       error (0, 0, "%s: hard link not allowed for directory", old);
  193.       return 1;
  194.     }
  195.   if (isdir (new))
  196.     {
  197.       /* Target is a directory; build the full filename. */
  198.       char *new_new;
  199.       char *old_base;
  200.  
  201.       old_base = basename (old);
  202.       new_new = (char *) alloca (strlen (old_base) + 1 + strlen (new) + 1);
  203.       sprintf (new_new, "%s/%s", new, old_base);
  204.       new = new_new;
  205.     }
  206.  
  207.   if (lstat (new, &new_stats) == 0)
  208.     {
  209.       if (S_ISDIR (new_stats.st_mode))
  210.     {
  211.       error (0, 0, "%s: cannot overwrite directory", new);
  212.       return 1;
  213.     }
  214.       if (interactive)
  215.     {
  216.       fprintf (stderr, "%s: replace `%s'? ", program_name, new);
  217.       if (!yesno ())
  218.         return 0;
  219.     }
  220.       else if (!remove_existing_files)
  221.     {
  222.       error (0, 0, "%s: File exists", new);
  223.       return 1;
  224.     }
  225.  
  226.       if (backup_type != none)
  227.     {
  228.       char *tmp_backup = find_backup_file_name (new);
  229.       if (tmp_backup == NULL)
  230.         error (1, 0, "virtual memory exhausted");
  231.       new_backup = alloca (strlen (tmp_backup) + 1);
  232.       strcpy (new_backup, tmp_backup);
  233.       free (tmp_backup);
  234.       if (rename (new, new_backup))
  235.         {
  236.           if (errno != ENOENT)
  237.         {
  238.           error (0, errno, "cannot backup `%s'", new);
  239.           return 1;
  240.         }
  241.           else
  242.         new_backup = NULL;
  243.         }
  244.     }
  245.       else if (unlink (new) && errno != ENOENT)
  246.     {
  247.       error (0, errno, "cannot remove old link to `%s'", new);
  248.       return 1;
  249.     }
  250.     }
  251.   else if (errno != ENOENT)
  252.     {
  253.       error (0, errno, "%s", new);
  254.       return 1;
  255.     }
  256.        
  257.   if (verbose)
  258.     printf ("%s -> %s\n", old, new);
  259.  
  260.   if ((*linkfunc) (old, new) == 0)
  261.     {
  262.       return 0;
  263.     }
  264.  
  265.   error (0, errno, "cannot %slink `%s' to `%s'",
  266. #ifdef S_ISLNK
  267.          linkfunc == symlink ? "symbolic " : "",
  268. #else
  269.          "",
  270. #endif
  271.          old, new);
  272.  
  273.   if (new_backup)
  274.     {
  275.       if (rename (new_backup, new))
  276.     error (0, errno, "cannot un-backup `%s'", new);
  277.     }
  278.   return 1;
  279. }
  280.  
  281. void
  282. usage ()
  283. {
  284.   fprintf (stderr, "\
  285. Usage: %s [options] source [dest]\n\
  286.        %s [options] source... directory\n\
  287. Options:\n\
  288.        [-bdfisvF] [-S backup-suffix] [-V {numbered,existing,simple}]\n\
  289.        [+version-control={numbered,existing,simple}] [+backup] [+directory]\n\
  290.        [+force] [+interactive] [+symbolic] [+verbose] [+suffix=backup-suffix]\n",
  291.        program_name, program_name);
  292.   exit (1);
  293. }
  294.